package jnpf.database.source.impl;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import jnpf.database.data.DataSourceContextHolder;
import jnpf.database.enums.datatype.DataTypeEnum;
import jnpf.database.enums.datatype.DtOracleEnum;
import jnpf.database.model.DataTypeModel;
import jnpf.database.model.DbTableFieldModel;
import jnpf.database.model.DbTableModel;
import jnpf.database.source.DbBase;
import jnpf.database.sql.SqlBase;
import jnpf.database.sql.impl.SqlOracle;
import jnpf.database.util.CommonUtil;
import jnpf.database.util.DataSourceUtil;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Properties;

/**
 * Oracle模型
 *
 * @author JNPF开发平台组 YY
 * @version V3.2.0
 * @copyright 引迈信息技术有限公司
 * @date 2021/10/06
 */
@Slf4j
public class DbOracle extends DbBase {

    public static final String DB_ENCODE = "Oracle";

    /*================Oracle4种数据库连接url=================*/
    /**
     * SID
     * 或：jdbc:oracle:thin:@{host}:{port}/{SID}
     * 默认配置：dbname = @SID
     */
    private static final String URL_SPLIT = ":@";
    private static final String SID_URL = "jdbc:oracle:thin:@{host}:{port}:{dbname}";
    private static final String SID_SIGN = "SID";
    /**
     * SERVICE：服务名
     * 配置：dbname = @SERVICE
     */
    private static final String SERVICE_URL = "jdbc:oracle:thin:@//{host}:{port}/{dbname}";
    private static final String SERVICE_SIGN = "SERVICE";
    /**
     * SCHEMA：模式
     * 配置：dbname = @SCHEMA
     */
    private static final String SCHEMA_URL =
            "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={host})(PORT={port})))(CONNECT_DATA=(SERVICE_NAME={dbname})))";
    private static final String SCHEMA_SIGN = "SCHEMA";
    /**
     * TNS
     * 配置：dbname = @TNS
     */
    private static final String TNS_URL = "jdbc:oracle:thin:@{dbname}";
    private static final String TNS_SIGN = "TNS";



    @Override
    public void setDbType() {
        mpDbType = DbType.ORACLE;
        connUrlEncode = "oracle";
        dbEncode = DB_ENCODE;
        driver = "oracle.jdbc.OracleDriver";
    }

    @Override
    public SqlBase getSqlBase() {
        return new SqlOracle(this);
    }

    @Override
    public DataTypeModel getDataTypeModel(DataTypeEnum dte){
        return dte.getDtOracleEnum().getDataTypeModel();
    }

    @Override
    public DataTypeModel getDataTypeModel(String dbFieldType) {
        for(DtOracleEnum dtOracleEnum : DtOracleEnum.values()){
            if(dbFieldType.equals(dtOracleEnum.getDbFieldType())){
                return dtOracleEnum.getDataTypeModel();
            }
        }
        return null;
    }

    @Override
    public String getConnUrl(String prepareUrl, String host, Integer port, String dbName) {
        String[] dbNameSplit = dbName.split(URL_SPLIT);
        if(dbNameSplit.length > 1){
            String urlType = dbNameSplit[dbNameSplit.length - 1];
            /* 这里有一个风险：由于客户url中dbname也刚好含有:@SERVICE或内包含多个:@，导致连接失败*/
            switch (urlType){
                case SID_SIGN:
                    prepareUrl = SID_URL;
                    break;
                case SERVICE_SIGN:
                    prepareUrl = SERVICE_URL;
                    break;
                case SCHEMA_SIGN:
                    prepareUrl = SCHEMA_URL;
                    break;
                case TNS_SIGN:
                    prepareUrl = TNS_URL;
                    break;
                default:
                    break;
            }
            dbName = dbNameSplit[dbNameSplit.length - 2];
        }else {
            /* prepareUrl：1、配置自定义提供，2、内置约定默认。
                优先级：":@类型“ > 自定义prepareUrl > 默认url */
            if(StringUtil.isEmpty(prepareUrl)){
                prepareUrl = SID_URL;
            }
        }
        return super.getConnUrl(prepareUrl, host, port, dbName);
    }

    public static Properties setConnProp(String prepareUserName, String password){
        String[] dbNameSplit = prepareUserName.split(URL_SPLIT);
        Properties conProps = new Properties();
        // 使用角色登录：userName + :@{角色}
        if(dbNameSplit.length > 1){
            String logonUser = dbNameSplit[dbNameSplit.length - 1];
            //defaultRowPrefetch：从服务器预取的默认行数(默认值为“10”) String (containing integer value)
            conProps.put("defaultRowPrefetch", "15");
            /* 这里有一个风险：由于客户userName中含有一个或多个:@导致连接失败 */
            //internal_logon：允许您作为sys登录的权限，如sysdba或sysoper
            conProps.put("internal_logon", logonUser);
            String userName = dbNameSplit[dbNameSplit.length - 2];
            conProps.put("user", userName);
        }else {
            conProps.put("user", prepareUserName);
        }
        conProps.setProperty("password", password);
        return conProps;
    }


    @Override
    public void setDynamicMap(HashMap<String, TableNameHandler> map, DbTableModel dbTableModel) {
        map.put(dbTableModel.getTable().toLowerCase(), (sql, tableName) -> DataSourceContextHolder.getDatasourceName().toUpperCase()+"."+dbTableModel.getTable());
    }

    @Override
    public DbTableFieldModel getFieldModel(ResultSet result) {
        return new DbTableFieldModel();
    }

    @Override
    public String getDbTime(Connection conn) {
        StringBuilder sql = new StringBuilder();
        sql.append("select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as TIME from dual");
        return dbTimeCommon(conn,sql);
    }

    @Override
    public String getReplaceSql(String sql, String table, DataSourceUtil dbSourceOrDbLink) {
        /**
         * 说明：一个实例对应一个数据库，多个模式，一个用户对应一个模式
         * 表空间需默认：JNPFCLOUD
         */
        return CommonUtil.getReplaceSql(sql, table, dbSourceOrDbLink,
                false,
                true,
                false);
    }


}
